#include "KeyRecommander.h"
#include "json.hpp"

bool MyCompare::operator()(const CandidateResult &lhs, const CandidateResult &rhs) {
    // 首先按编辑距离升序排序，距离较小的优先
    if (lhs._dist == rhs._dist) {
        // 如果编辑距离相同，则按频率降序排序
        return lhs._freq < rhs._freq;
    }
    return lhs._dist > rhs._dist;
}

int triple_min(const int &a, const int &b, const int &c);
std::size_t length(const std::string &str);
size_t nBytesCode(const char ch);

KeyRecommander::KeyRecommander(string &query, const TcpConnectionPtr &conn, Dictionary *dict)
    : _queryWord(query), _conn(conn), _dict(dict) {
    for (char &c : _queryWord) {
        c = tolower(c); // 将每个字符转换为小写
    }
}

void KeyRecommander::execute() {
    queryIndexTable(); // 查询索引表
    response();        // 响应客户端
}

void KeyRecommander::queryIndexTable() {
    // 首先打开字典
    map<std::string, std::set<int>> eng_Index = _dict->getEngIndexTable();
    map<std::string, std::set<int>> chs_Index = _dict->getChsIndexTable();

    //  总字符集合
    set<int> eng_indx_all;
    set<int> chs_indx_all;

    // 遍历每个字符
    for (int idx = 0; idx < _queryWord.size();) {
        size_t len = nBytesCode(_queryWord[idx]);
        if (len == 1) {
            // 英文字符
            string word(1, _queryWord[idx]);
            eng_indx_all.insert(eng_Index[word].begin(), eng_Index[word].end());
            ++idx;
        } else {
            // 中文字符
            string ch_str = _queryWord.substr(idx, len);
            chs_indx_all.insert(chs_Index[ch_str].begin(), chs_Index[ch_str].end());
            idx += 3;
        }
    }

    // 字符串读取完毕，已经取出字符对应索引的集合
    // 交给statistic计算频率和距离
    statistic(eng_indx_all, chs_indx_all);
}

// 统计候选结果，并加入优先队列
void KeyRecommander::statistic(set<int> &eng_idx_set, set<int> &chs_idx_set) {
    // 英文索引查找
    vector<std::pair<std::string, int>> eng_dict_vec = _dict->getEngDict();
    for (auto &idx : eng_idx_set) {
        CandidateResult candy;
        candy._word = eng_dict_vec[idx].first;
        candy._freq = eng_dict_vec[idx].second;
        candy._dist = distance(candy._word);
        _resultQue.push(candy);
    }

    // 中文索引查找
    vector<std::pair<std::string, int>> chs_dict_vec = _dict->getChsDict();
    for (auto &idx : chs_idx_set) {
        CandidateResult candy;
        candy._word = chs_dict_vec[idx].first;
        candy._freq = chs_dict_vec[idx].second;
        candy._dist = distance(candy._word);
        _resultQue.push(candy);
    }
}

void KeyRecommander::response() {
    nlohmann::json resultJson;
    for (int i = 0; i < 5; ++i) {
        resultJson.push_back(_resultQue.top()._word);
        _resultQue.pop();
    }

    string jsonStr = resultJson.dump(); // 反序列化

    // 组装成 http响应体
    std::string response = "HTTP/1.1 200 OK\r\n";
    response += "Content-Type: application/json\r\n";
    response += "Content-Length: " + std::to_string(jsonStr.size()) + "\r\n";

    // 添加 CORS 头部
    response += "Access-Control-Allow-Origin: *\r\n";                            // 允许所有来源跨域访问
    response += "Access-Control-Allow-Methods: GET, POST, OPTIONS\r\n";          // 允许的 HTTP 方法
    response += "Access-Control-Allow-Headers: Content-Type, Authorization\r\n"; // 允许的请求头

    response += "\r\n"; // 空行，表示头部结束
    response += jsonStr;
    response += "\r\n"; // 空行，表示体结束

    _conn->sendInLoop(response);
}

////////////////////////////////////////////////
/////               计算距离                /////
////////////////////////////////////////////////

int KeyRecommander::distance(const string &rhs) {
    string lhs = _queryWord;

    // 计算最小编辑距离-包括处理中英文
    size_t lhs_len = length(lhs);
    size_t rhs_len = length(rhs);
    int editDist[lhs_len + 1][rhs_len + 1];

    // 初始化编辑距离矩阵的第一行和第一列
    for (size_t idx = 0; idx <= lhs_len; ++idx) {
        editDist[idx][0] = idx;
    }
    for (size_t idx = 0; idx <= rhs_len; ++idx) {
        editDist[0][idx] = idx;
    }

    // 进行编辑距离计算，动态规划算法
    string sublhs, subrhs;
    for (size_t dist_i = 1, lhs_idx = 0; dist_i <= lhs_len; ++dist_i, ++lhs_idx) {
        size_t nBytes = nBytesCode(lhs[lhs_idx]);
        sublhs = lhs.substr(lhs_idx, nBytes); // 获取当前字符片段
        lhs_idx += (nBytes - 1);

        for (std::size_t dist_j = 1, rhs_idx = 0; dist_j <= rhs_len; ++dist_j, ++rhs_idx) {
            nBytes = nBytesCode(rhs[rhs_idx]);
            subrhs = rhs.substr(rhs_idx, nBytes); // 获取目标字符串的字符片段
            rhs_idx += (nBytes - 1);

            if (sublhs == subrhs) {
                editDist[dist_i][dist_j] = editDist[dist_i - 1][dist_j - 1]; // 如果相等，不修改距离
            } else {
                editDist[dist_i][dist_j] = triple_min(
                    editDist[dist_i][dist_j - 1] + 1,    // 删除操作
                    editDist[dist_i - 1][dist_j] + 1,    // 插入操作
                    editDist[dist_i - 1][dist_j - 1] + 1 // 替换操作
                );
            }
        }
    }

    return editDist[lhs_len][rhs_len]; // 返回最终的编辑距离
}

// 获取最小值的辅助函数
int triple_min(const int &a, const int &b, const int &c) {
    return a < b ? (a < c ? a : c) : (b < c ? b : c);
}

// 获取字符串的长度，处理中文字符的字节数
std::size_t length(const std::string &str) {
    std::size_t ilen = 0;
    for (std::size_t idx = 0; idx != str.size(); ++idx) {
        int nBytes = nBytesCode(str[idx]);
        idx += (nBytes - 1);
        ++ilen;
    }
    return ilen;
}

// 计算字符的字节数（主要用于处理多字节字符，如中文）
size_t nBytesCode(const char ch) {
    if (ch & (1 << 7)) {
        int nBytes = 1;
        for (int idx = 0; idx != 6; ++idx) {
            if (ch & (1 << (6 - idx))) {
                ++nBytes;
            } else
                break;
        }
        return nBytes;
    }
    return 1;
}
